#include <stdio.h>

#include <stdlib.h>



/*

  Compile thusly:



  cc -o yuv2ppm yuv2ppm.c

*/



/* example.ppm

P3

# feep.ppm

4 4

15

 0  0  0    0  0  0    0  0  0   15  0 15

 0  0  0    0 15  7    0  0  0    0  0  0

 0  0  0    0  0  0    0 15  7    0  0  0

15  0 15    0  0  0    0  0  0    0  0  0

*/

/*

  Use "P6" for binary data, or "P3" for ascii data.

 */



int make_outfile(char *outfile, char *infile)

{

   int i;

   

   for(i=0; infile[i]; i++)

      outfile[i] = infile[i];



   outfile[i++] = '.';

   outfile[i++] = 'p';

   outfile[i++] = 'p';

   outfile[i++] = 'm';

   outfile[i++] = 0;

   

   return 0;

}





int yuv2rgb(int y, int u, int v)

{

   unsigned int pixel32;

   unsigned char *pixel = (unsigned char *)&pixel32;

   int r, g, b;

   

#if 0

   /*

     One formula I found:  (not the right one)

    

     R = 1.164(Y - 16) + 1.596(Cr - 128)

     G = 1.164(Y - 16) - 0.813(Cr - 128) - 0.391(Cb - 128)

     B = 1.164(Y - 16)                   + 2.018(Cb - 128)

   */

      

   r = (1.164 * (y - 16))

      + (2.018 * (v - 128));

   g = (1.164 * (y - 16))

      - (0.813 * (u - 128))

      - (0.391 * (v - 128));

   b = (1.164 * (y - 16))

      + (1.596 * (u - 128));

#else

   /*

     Another formula I found:  (seems to work)

     

     R = Y + 1.370705 (V-128)

     G = Y - 0.698001 (V-128) - 0.337633 (U-128)

     B = Y + 1.732446 (U-128)

   */

   

   r = y + (1.370705 * (v-128));

   g = y - (0.698001 * (v-128)) - (0.337633 * (u-128));

   b = y + (1.732446 * (u-128));

#endif



   // Even with proper conversion, some values still need clipping.

   if (r > 255) r = 255;

   if (g > 255) g = 255;

   if (b > 255) b = 255;

   if (r < 0) r = 0;

   if (g < 0) g = 0;

   if (b < 0) b = 0;



   // Values only go from 0-220..  Why?

   pixel[0] = r * 220 / 256;

   pixel[1] = g * 220 / 256;

   pixel[2] = b * 220 / 256;

   pixel[3] = 0;



   /* Debug

   printf("yuv2rgb(%i, %i, %i) -> %i, %i, %i  (0x%x)\n",

	  y, u, v,

	  pixel[0], pixel[1], pixel[2],

	  pixel32);

   */

   

   return pixel32;

}



int yuv2ppm(char *infile, char *outfile)

{

   FILE *in, *out;

   int i;

   unsigned int pixel_16;

   unsigned char pixel_24[3];

   unsigned int pixel32;

   int y, u, v, y2;

   

   char *ppmheader = "P6\n# Generated by yuv2ppm\n720 486\n255\n";



   in = fopen(infile, "rb");

   out = fopen(outfile, "wb");



   if (!in  ||  !out)  return 0;



   fprintf(out, ppmheader);



   for(i=0; i<720*486/2; i++)

   {

      fread(&pixel_16, 4, 1, in);



      pixel_24[0] = pixel_24[1] = pixel_24[2] = 0;

      

      u  = ((pixel_16 & 0x000000ff));

      y  = ((pixel_16 & 0x0000ff00)>>8);

      v  = ((pixel_16 & 0x00ff0000)>>16);

      y2 = ((pixel_16 & 0xff000000)>>24);





      pixel32 = yuv2rgb(y, u, v);

      pixel_24[0] = (pixel32 & 0x000000ff);

      pixel_24[1] = (pixel32 & 0x0000ff00) >> 8;

      pixel_24[2] = (pixel32 & 0x00ff0000) >> 16;

      

      // For binary PPM

      fwrite(pixel_24, 3, 1, out);

      // For ascii PPM

      //fprintf(out, "%i %i %i\n",

      //	 pixel_24[0],

      //	 pixel_24[1],

      //	 pixel_24[2]);

      

      pixel32 = yuv2rgb(y2, u, v);

      pixel_24[0] = (pixel32 & 0x000000ff);

      pixel_24[1] = (pixel32 & 0x0000ff00) >> 8;

      pixel_24[2] = (pixel32 & 0x00ff0000) >> 16;



      // For binary PPM

      fwrite(pixel_24, 3, 1, out);

      // For ascii PPM

      //fprintf(out, "%i %i %i\n",

      //	 pixel_24[0],

      //	 pixel_24[1],

      //	 pixel_24[2]);

	 



   }



   fclose(in);

   fclose(out);



   return 1;

}



int main(int argc, char **argv)

{

  char *infile, outfile[256];

  int i;

  int success;

  

  for(i=1; i<argc; i++)

  {

     success = 0;

     infile = argv[i];

     make_outfile(outfile, infile);

     

     printf("%s -> %s...  ", infile, outfile);

     fflush(stdout);



     success = yuv2ppm(infile, outfile);

     

     if(success)

     {

	printf("Done.\n");

     }

     else

     {

	printf("Failed.  Aborting.\n");

	return 1;

     }

  }



  return 0;

}

